home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / comm / term / term41source.lha / Extras / Source / term-Source.lha / termBuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-26  |  33.6 KB  |  1,835 lines

  1. /*
  2. **    termBuffer.c
  3. **
  4. **    Auxilary routines for text buffer/capture management.
  5. **
  6. **    Copyright © 1990-1994 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Search string window gadgets. */
  13.  
  14. enum    {    GAD_STRING,GAD_OK,GAD_CANCEL };
  15.  
  16.     /* Maximum size of an allocated line string. */
  17.  
  18. #define STRING_SIZE    (1 + 255 + 1)
  19.  
  20.     /* How many strings to include in a single puddle. */
  21.  
  22. #define STRING_COUNT    10
  23.  
  24.     /* The number of lines the buffer will grow. */
  25.  
  26. #define BUFFER_GROW    100
  27.  
  28.     /* Memory pool header. */
  29.  
  30. STATIC APTR        BufferPoolHeader;
  31.  
  32.     /* Word separator characters. */
  33.  
  34. STATIC BYTE WordSeparators[256] =
  35. {
  36.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  37.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  38.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  39.     0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
  40.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  41.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  42.     1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  43.     0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
  44.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  45.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  46.     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  47.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  48.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  49.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
  50.     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  51.     0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0
  52. };
  53.  
  54.     /* AllocString(STRPTR String,WORD Len):
  55.      *
  56.      +    Allocate space for a string, new pooled version.
  57.      */
  58.  
  59. STATIC STRPTR __regargs
  60. AllocString(STRPTR String,LONG Len)
  61. {
  62.     STRPTR Mem;
  63.  
  64.     if(Len > 255)
  65.         Len = 255;
  66.  
  67.     if(Mem = (STRPTR)LibAllocPooled(BufferPoolHeader,1 + Len + 1))
  68.     {
  69.         *Mem++ = Len;
  70.  
  71.         if(Len)
  72.             CopyMem(String,Mem,Len);
  73.  
  74.         Mem[Len] = 0;
  75.  
  76.         return((STRPTR)Mem);
  77.     }
  78.     else
  79.         return(NULL);
  80. }
  81.  
  82.     /* FreeString(STRPTR String):
  83.      *
  84.      *    Free the space occupied by a string, new pooled version.
  85.      */
  86.  
  87. STATIC VOID __regargs
  88. FreeString(STRPTR String)
  89. {
  90.     LibFreePooled(BufferPoolHeader,&String[-1],1 + String[-1] + 1);
  91. }
  92.  
  93.     /* AddLine(STRPTR Line,LONG Size):
  94.      *
  95.      *    Add a line to the display buffer.
  96.      */
  97.  
  98. VOID __regargs
  99. AddLine(register STRPTR Line,register LONG Size)
  100. {
  101.         /* Are we still to update the buffer contents? */
  102.  
  103.     if(!BufferClosed)
  104.     {
  105.             /* Remove trailing spaces. */
  106. /*
  107.         while(Size > 0 && Line[Size - 1] == ' ')
  108.             Size--;
  109. */
  110.             /* Is the buffer array initialized? */
  111.  
  112.         if(BufferLines)
  113.         {
  114.             ULONG Signals = 0;
  115.  
  116.                 /* Pick up the global access semaphore
  117.                  * (two tasks are sharing the data).
  118.                  */
  119.  
  120.             ObtainSemaphore(BufferSemaphore);
  121.  
  122.                 /* Check for limit. */
  123.  
  124.             if(Config -> CaptureConfig -> MaxBufferSize && BufferSpace >= Config -> CaptureConfig -> MaxBufferSize)
  125.             {
  126.                 register LONG i;
  127.  
  128.                 BufferSpace -= BufferLines[0][-1];
  129.  
  130.                 FreeString(BufferLines[0]);
  131.  
  132.                 for(i = 1 ; i < MaxLines ; i++)
  133.                     BufferLines[i - 1] = BufferLines[i];
  134.  
  135.                 Lines--;
  136.  
  137.                     /* Tell the buffer task to
  138.                      * refresh the display.
  139.                      */
  140.  
  141.                 Signals = SIG_MOVEUP;
  142.             }
  143.             else
  144.             {
  145.                     /* We've reached the last line in the buffer. */
  146.  
  147.                 if(Lines == MaxLines)
  148.                 {
  149.                     STRPTR *MoreBuffer;
  150.  
  151.                         /* Allocate space for some more lines. */
  152.  
  153.                     if(MoreBuffer = (STRPTR *)AllocVecPooled((MaxLines + BUFFER_GROW) * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR))
  154.                     {
  155.                         register LONG i;
  156.  
  157.                         BufferChanged = TRUE;
  158.  
  159.                             /* Copy the old lines to the new
  160.                              * buffer.
  161.                              */
  162.  
  163.                         for(i = 0 ; i < Lines ; i++)
  164.                             MoreBuffer[i] = BufferLines[i];
  165.  
  166.                             /* Free the old lines. */
  167.  
  168.                         FreeVecPooled(BufferLines);
  169.  
  170.                             /* Set the new buffer. */
  171.  
  172.                         MaxLines += BUFFER_GROW;
  173.  
  174.                         BufferLines = MoreBuffer;
  175.                     }
  176.                     else
  177.                     {
  178.                         BufferChanged = TRUE;
  179.  
  180.                             /* We couldn't get enough memory
  181.                              * to extend the number of lines
  182.                              * in the buffer, so we'll have
  183.                              * to wrap the contents of the
  184.                              * buffer around.
  185.                              */
  186.  
  187.                         if(Lines)
  188.                         {
  189.                             register LONG i;
  190.  
  191.                             BufferSpace -= BufferLines[0][-1];
  192.  
  193.                             FreeString(BufferLines[0]);
  194.  
  195.                             for(i = 1 ; i < MaxLines ; i++)
  196.                                 BufferLines[i - 1] = BufferLines[i];
  197.  
  198.                             Lines--;
  199.  
  200.                                 /* Tell the buffer task to
  201.                                  * refresh the display.
  202.                                  */
  203.  
  204.                             Signals = SIG_MOVEUP;
  205.                         }
  206.                     }
  207.                 }
  208.             }
  209.  
  210.                 /* Allocate a new line and copy the buffer contents
  211.                  * into it.
  212.                  */
  213.  
  214.             if(BufferLines[Lines] = AllocString(Line,Size))
  215.             {
  216.                 BufferChanged = TRUE;
  217.  
  218.                 Lines++;
  219.  
  220.                 BufferSpace += Size;
  221.             }
  222.  
  223.             ReleaseSemaphore(BufferSemaphore);
  224.  
  225.                 /* Tell the buffer task to update the display. */
  226.  
  227.             if(!Signals)
  228.             {
  229.                 Signals = SIG_UPDATE;
  230.  
  231.                 UpdateReview(FALSE);
  232.             }
  233.             else
  234.                 UpdateReview(TRUE);
  235.  
  236.             ObtainSemaphore(&BufferTaskSemaphore);
  237.  
  238.             if(BufferTask && Signals)
  239.             {
  240.                 Forbid();
  241.  
  242.                 ClrSignal(SIG_HANDSHAKE);
  243.  
  244.                 Signal(BufferTask,Signals);
  245.  
  246.                 Wait(SIG_HANDSHAKE);
  247.  
  248.                 Permit();
  249.             }
  250.  
  251.             ReleaseSemaphore(&BufferTaskSemaphore);
  252.         }
  253.     }
  254. }
  255.  
  256.     /* StoreBuffer(APTR Buffer,LONG Size):
  257.      *
  258.      *    Store data in the display buffer.
  259.      */
  260.  
  261. VOID __regargs
  262. StoreBuffer(register STRPTR Buffer,register LONG Size,register COPTR OutputRoutine)
  263. {
  264.     STATIC UBYTE __far    LineBuffer[BUFFER_LINE_MAX + 1];
  265.     STATIC LONG          BufferCount    = 0,
  266.                 BufferIndex    = 0;
  267.     STATIC BOOL        InEscape    = FALSE,
  268.                 InCSI        = FALSE;
  269.  
  270.     LONG BufferWidth = Config -> CaptureConfig -> BufferWidth;
  271.  
  272.     register UBYTE c;
  273.  
  274.     if(Size > 0)
  275.     {
  276.         if(InEscape)
  277.         {
  278.             if(*Buffer == '[')
  279.             {
  280.                 Buffer++;
  281.  
  282.                 InEscape    = FALSE;
  283.                 InCSI        = TRUE;
  284.  
  285.                 while(Size-- > 0)
  286.                 {
  287.                     c = *Buffer++;
  288.  
  289.                     if(c >= '@' || c < ' ')
  290.                     {
  291.                         InCSI = FALSE;
  292.  
  293.                         break;
  294.                     }
  295.                 }
  296.             }
  297.             else
  298.             {
  299.                 if(*Buffer++ >= '0')
  300.                     InEscape = InCSI = FALSE;
  301.  
  302.                 Size--;
  303.             }
  304.         }
  305.  
  306.         if(InCSI)
  307.         {
  308.             while(Size-- > 0)
  309.             {
  310.                 c = *Buffer++;
  311.  
  312.                 if(c >= '@' || c < ' ')
  313.                 {
  314.                     InCSI = FALSE;
  315.  
  316.                     break;
  317.                 }
  318.             }
  319.         }
  320.     }
  321.  
  322.     if(Config -> TerminalConfig -> FontMode == FONT_STANDARD)
  323.     {
  324.         while(Size-- > 0)
  325.         {
  326.                 /* Look which char we are to handle. */
  327.  
  328.             switch(c = *Buffer++)
  329.             {
  330.                     /* Escape sequence. */
  331.  
  332.                 case ESC:
  333.  
  334.                     InEscape = TRUE;
  335.  
  336.                     while(Size-- > 0)
  337.                     {
  338.                         if(*Buffer == '[')
  339.                         {
  340.                             Buffer++;
  341.  
  342.                             InEscape    = FALSE;
  343.                             InCSI        = TRUE;
  344.  
  345.                             while(Size-- > 0)
  346.                             {
  347.                                 c = *Buffer++;
  348.  
  349.                                 if(c >= '@' || c < ' ')
  350.                                 {
  351.                                     InCSI = FALSE;
  352.  
  353.                                     break;
  354.                                 }
  355.                             }
  356.  
  357.                             break;
  358.                         }
  359.                         else
  360.                         {
  361.                             if(*Buffer++ >= '0')
  362.                             {
  363.                                 InEscape = InCSI = FALSE;
  364.  
  365.                                 break;
  366.                             }
  367.                         }
  368.                     }
  369.  
  370.                     if(InCSI)
  371.                     {
  372.                         while(Size-- > 0)
  373.                         {
  374.                             c = *Buffer++;
  375.  
  376.                             if(c >= '@' || c < ' ')
  377.                             {
  378.                                 InCSI = FALSE;
  379.  
  380.                                 break;
  381.                             }
  382.                         }
  383.                     }
  384.  
  385.                     break;
  386.  
  387.                     /* Control sequence. */
  388.  
  389.                 case CSI:
  390.  
  391.                     InEscape    = FALSE;
  392.                     InCSI        = TRUE;
  393.  
  394.                     while(Size-- > 0)
  395.                     {
  396.                         c = *Buffer++;
  397.  
  398.                         if(c >= '@' || c < ' ')
  399.                         {
  400.                             InCSI = FALSE;
  401.  
  402.                             break;
  403.                         }
  404.                     }
  405.  
  406.                     break;
  407.  
  408.                     /* Move the cursor one step back. */
  409.  
  410.                 case BKS:
  411.  
  412.                     if(BufferCount > 0)
  413.                         BufferCount--;
  414.  
  415.                     if(BufferIndex > 0)
  416.                         BufferIndex--;
  417.  
  418.                     if(BufferCount < BufferIndex)
  419.                         BufferIndex = BufferCount;
  420.  
  421.                     break;
  422.  
  423.                     /* Move the cursor to the next tab
  424.                      * stop.
  425.                      */
  426.  
  427.                 case TAB:
  428.  
  429.                     if(((BufferIndex + 8) & ~7) < BufferWidth)
  430.                     {
  431.                         register LONG Skip = ((BufferIndex + 8) & ~7);
  432.  
  433.                         if(Skip > BufferCount)
  434.                         {
  435.                             register LONG Delta = Skip - BufferCount;
  436.  
  437.                             memset(&LineBuffer[BufferCount],' ',Delta);
  438.                         }
  439.  
  440.                         BufferIndex = Skip;
  441.                     }
  442.                     else
  443.                     {
  444.                         (*OutputRoutine)(LineBuffer,BufferCount);
  445.  
  446.                         BufferCount = BufferIndex = 0;
  447.                     }
  448.  
  449.                     break;
  450.  
  451.                     /* Move cursor to first character in line. */
  452.  
  453.                 case RET:
  454.  
  455.                     BufferIndex = 0;
  456.  
  457.                     break;
  458.  
  459.                     /* Terminate the current line. */
  460.  
  461.                 case ENT:
  462.  
  463.                     (*OutputRoutine)(LineBuffer,BufferCount);
  464.  
  465.                     BufferCount = BufferIndex = 0;
  466.  
  467.                     break;
  468.  
  469.                     /* Stuff the character into the buffer. */
  470.  
  471.                 default:
  472.  
  473.                     if(IsGlyph[c])
  474.                     {
  475.                         LineBuffer[BufferIndex++] = c;
  476.  
  477.                         if(BufferIndex > BufferCount)
  478.                             BufferCount = BufferIndex;
  479.                     }
  480.  
  481.                     break;
  482.             }
  483.  
  484.                 /* The line is full, add it to the display buffer. */
  485.  
  486.             if(BufferCount >= BufferWidth)
  487.             {
  488.                 (*OutputRoutine)(LineBuffer,BufferCount);
  489.  
  490.                 BufferCount = BufferIndex = 0;
  491.             }
  492.         }
  493.     }
  494.     else
  495.     {
  496.         while(Size-- > 0)
  497.         {
  498.                 /* Look which char we are to handle. */
  499.  
  500.             switch(c = *Buffer++)
  501.             {
  502.                     /* Escape sequence. */
  503.  
  504.                 case ESC:
  505.  
  506.                     InEscape = TRUE;
  507.  
  508.                     while(Size-- > 0)
  509.                     {
  510.                         if(*Buffer == '[')
  511.                         {
  512.                             Buffer++;
  513.  
  514.                             InEscape    = FALSE;
  515.                             InCSI        = TRUE;
  516.  
  517.                             while(Size-- > 0)
  518.                             {
  519.                                 c = *Buffer++;
  520.  
  521.                                 if(c >= '@' || c < ' ')
  522.                                 {
  523.                                     InCSI = FALSE;
  524.  
  525.                                     break;
  526.                                 }
  527.                             }
  528.  
  529.                             break;
  530.                         }
  531.                         else
  532.                         {
  533.                             if(*Buffer++ >= '0')
  534.                             {
  535.                                 InEscape = InCSI = FALSE;
  536.  
  537.                                 break;
  538.                             }
  539.                         }
  540.                     }
  541.  
  542.                     if(InCSI)
  543.                     {
  544.                         while(Size-- > 0)
  545.                         {
  546.                             c = *Buffer++;
  547.  
  548.                             if(c >= '@' || c < ' ')
  549.                             {
  550.                                 InCSI = FALSE;
  551.  
  552.                                 break;
  553.                             }
  554.                         }
  555.                     }
  556.  
  557.                     break;
  558.  
  559.                     /* Control sequence. */
  560.  
  561.                 case CSI:
  562.  
  563.                     InEscape    = FALSE;
  564.                     InCSI        = TRUE;
  565.  
  566.                     while(Size-- > 0)
  567.                     {
  568.                         c = *Buffer++;
  569.  
  570.                         if(c >= '@' || c < ' ')
  571.                         {
  572.                             InCSI = FALSE;
  573.  
  574.                             break;
  575.                         }
  576.                     }
  577.  
  578.                     break;
  579.  
  580.                     /* Move the cursor one step back. */
  581.  
  582.                 case BKS:
  583.  
  584.                     if(BufferCount > 0)
  585.                         BufferCount--;
  586.  
  587.                     if(BufferIndex > 0)
  588.                         BufferIndex--;
  589.  
  590.                     if(BufferCount < BufferIndex)
  591.                         BufferIndex = BufferCount;
  592.  
  593.                     break;
  594.  
  595.                     /* Move the cursor to the next tab
  596.                      * stop.
  597.                      */
  598.  
  599.                 case TAB:
  600.  
  601.                     if(((BufferIndex + 8) & ~7) < BufferWidth)
  602.                     {
  603.                         register LONG Skip = ((BufferIndex + 8) & ~7);
  604.  
  605.                         if(Skip > BufferCount)
  606.                         {
  607.                             register LONG Delta = Skip - BufferCount;
  608.  
  609.                             memset(&LineBuffer[BufferCount],' ',Delta);
  610.                         }
  611.  
  612.                         BufferIndex = Skip;
  613.                     }
  614.                     else
  615.                     {
  616.                         (*OutputRoutine)(LineBuffer,BufferCount);
  617.  
  618.                         BufferCount = BufferIndex = 0;
  619.                     }
  620.  
  621.                     break;
  622.  
  623.                     /* Move cursor to first character in line. */
  624.  
  625.                 case RET:
  626.  
  627.                     BufferIndex = 0;
  628.  
  629.                     break;
  630.  
  631.                     /* Terminate the current line. */
  632.  
  633.                 case ENT:
  634.  
  635.                     (*OutputRoutine)(LineBuffer,BufferCount);
  636.  
  637.                     BufferCount = BufferIndex = 0;
  638.  
  639.                     break;
  640.  
  641.                     /* Stuff the character into the buffer. */
  642.  
  643.                 default:
  644.  
  645.                     if(c)
  646.                     {
  647.                         LineBuffer[BufferIndex++] = c;
  648.  
  649.                         if(BufferIndex > BufferCount)
  650.                             BufferCount = BufferIndex;
  651.                     }
  652.  
  653.                     break;
  654.             }
  655.  
  656.                 /* The line is full, add it to the display buffer. */
  657.  
  658.             if(BufferCount >= BufferWidth)
  659.             {
  660.                 (*OutputRoutine)(LineBuffer,BufferCount);
  661.  
  662.                 BufferCount = BufferIndex = 0;
  663.             }
  664.         }
  665.     }
  666. }
  667.  
  668.     /* DeleteBuffer():
  669.      *
  670.      *    Delete buffer resources.
  671.      */
  672.  
  673. VOID
  674. DeleteBuffer()
  675. {
  676.     if(BufferLines)
  677.     {
  678.         FreeVecPooled(BufferLines);
  679.  
  680.         BufferLines = NULL;
  681.     }
  682.  
  683.     if(BufferPoolHeader)
  684.     {
  685.         LibDeletePool(BufferPoolHeader);
  686.  
  687.         BufferPoolHeader = NULL;
  688.     }
  689.  
  690.     if(BufferSemaphore)
  691.     {
  692.         FreeVecPooled(BufferSemaphore);
  693.  
  694.         BufferSemaphore = NULL;
  695.     }
  696. }
  697.  
  698.     /* CreateBuffer():
  699.      *
  700.      *    Allocate buffer resources.
  701.      */
  702.  
  703. BYTE
  704. CreateBuffer()
  705. {
  706.     if(BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  707.     {
  708.         if(BufferSemaphore = (struct SignalSemaphore *)AllocVecPooled(sizeof(struct SignalSemaphore),MEMF_ANY | MEMF_PUBLIC))
  709.         {
  710.             InitSemaphore(BufferSemaphore);
  711.  
  712.                 /* Create a memory pool header if possible. */
  713.  
  714.             if(BufferPoolHeader = LibCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
  715.                 return(TRUE);
  716.         }
  717.  
  718.         FreeVecPooled(BufferLines);
  719.  
  720.         BufferLines = NULL;
  721.     }
  722.  
  723.     return(FALSE);
  724. }
  725.  
  726.     /* FreeBuffer():
  727.      *
  728.      *    Release the contents of the text buffer.
  729.      */
  730.  
  731. VOID
  732. FreeBuffer()
  733. {
  734.         /* Free the contents of the display buffer. */
  735.  
  736.     if(BufferLines)
  737.     {
  738.         APTR NewPoolHeader;
  739.  
  740.         ObtainSemaphore(BufferSemaphore);
  741.  
  742.             /* If a new pool header is available, free the old
  743.              * pool and replace it with the new pool.
  744.              */
  745.  
  746.         if(NewPoolHeader = LibCreatePool(MEMF_ANY | MEMF_PUBLIC,STRING_SIZE * STRING_COUNT,STRING_SIZE * STRING_COUNT))
  747.         {
  748.             LibDeletePool(BufferPoolHeader);
  749.  
  750.             BufferPoolHeader = NewPoolHeader;
  751.         }
  752.         else
  753.         {
  754.             LONG i;
  755.  
  756.             for(i = 0 ; i < Lines ; i++)
  757.             {
  758.                 if(BufferLines[i])
  759.                     FreeString(BufferLines[i]);
  760.             }
  761.         }
  762.  
  763.         FreeVecPooled(BufferLines);
  764.  
  765.         Lines = 0;
  766.  
  767.         MaxLines = BUFFER_GROW;
  768.  
  769.         BufferLines = (STRPTR *)AllocVecPooled(MaxLines * sizeof(STRPTR),MEMF_ANY | MEMF_CLEAR);
  770.  
  771.         ReleaseSemaphore(BufferSemaphore);
  772.  
  773.         UpdateReview(TRUE);
  774.     }
  775.  
  776.     BufferSpace = 0;
  777.  
  778.     BufferChanged = FALSE;
  779. }
  780.  
  781.     /* DeleteSearchInfo(struct SearchInfo *Info):
  782.      *
  783.      *    Free buffer allocated by CreateSearchInfo().
  784.      */
  785.  
  786. VOID __regargs
  787. DeleteSearchInfo(struct SearchInfo *Info)
  788. {
  789.     if(Info)
  790.         FreeVecPooled(Info);
  791. }
  792.  
  793.     /* CreateSearchInfo(STRPTR Pattern):
  794.      *
  795.      *    Create auxilary data required by SearchTextBuffer().
  796.      */
  797.  
  798. struct SearchInfo * __regargs
  799. CreateSearchInfo(STRPTR Pattern,BOOLEAN Forward,BOOLEAN IgnoreCase,BOOLEAN WholeWords)
  800. {
  801.     struct SearchInfo *Info;
  802.  
  803.         /* Allocate the buffer. */
  804.  
  805.     if(Info = (struct SearchInfo *)AllocVecPooled(sizeof(struct SearchInfo),MEMF_ANY | MEMF_PUBLIC))
  806.     {
  807.         WORD i;
  808.  
  809.             /* Determine pattern width. */
  810.  
  811.         Info -> PatternWidth    = strlen(Pattern);
  812.         Info -> IgnoreCase    = IgnoreCase;
  813.  
  814.         if(Info -> PatternWidth == 1)
  815.         {
  816.             if(WordSeparators[Pattern[0]])
  817.                 WholeWords = FALSE;
  818.         }
  819.  
  820.         Info -> WholeWords = WholeWords;
  821.  
  822.             /* Turn the pattern into upper case characters. */
  823.  
  824.         if(IgnoreCase)
  825.         {
  826.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  827.                 Info -> Pattern[i] = ToUpper(Pattern[i]);
  828.         }
  829.         else
  830.         {
  831.             for(i = 0 ; i <= Info -> PatternWidth ; i++)
  832.                 Info -> Pattern[i] = Pattern[i];
  833.         }
  834.  
  835.             /* Fill the entire range with the maximum pattern width. */
  836.  
  837.         for(i = 0 ; i < 256 ; i++)
  838.             Info -> Distance[i] = Info -> PatternWidth;
  839.  
  840.             /* Fill in the matching distances. */
  841.  
  842.         if(Forward)
  843.         {
  844.             for(i = 0 ; i < Info -> PatternWidth - 1 ; i++)
  845.                 Info -> Distance[Info -> Pattern[i]] = Info -> PatternWidth - 1 - i;
  846.         }
  847.         else
  848.         {
  849.             for(i = Info -> PatternWidth - 1 ; i > 0 ; i--)
  850.                 Info -> Distance[Info -> Pattern[i]] = i;
  851.         }
  852.  
  853.             /* Restart from scratch. */
  854.  
  855.         Info -> FoundY    = -1;
  856.         Info -> Forward    = Forward;
  857.     }
  858.  
  859.     return(Info);
  860. }
  861.  
  862.     /* SearchTextBuffer():
  863.      *
  864.      *    String search function, based on the Boyer-Moore search
  865.      *    algorithm.
  866.      */
  867.  
  868. LONG __regargs
  869. SearchTextBuffer(struct SearchInfo *Info)
  870. {
  871.     if(BufferLines)
  872.     {
  873.         UBYTE    *Distance,
  874.             *Pattern;
  875.         WORD    LineWidth,
  876.             PatternWidth;
  877.         STRPTR    Line;
  878.  
  879.         LONG    i;
  880.         WORD    SearchPosition,PatternIndex,LineIndex,LastSearchPosition;
  881.  
  882.             /* Extract the relevant data. */
  883.  
  884.         Distance    = Info -> Distance;
  885.         Pattern        = Info -> Pattern;
  886.         PatternWidth    = Info -> PatternWidth;
  887.  
  888.         if(Info -> WholeWords)
  889.         {
  890.                 /* Which direction are we to search? */
  891.  
  892.             if(Info -> IgnoreCase)
  893.             {
  894.                 if(Info -> Forward)
  895.                 {
  896.                         /* Update the search positions. */
  897.  
  898.                     if(Info -> FoundY == -1)
  899.                     {
  900.                         Info -> FoundX        = 0;
  901.                         Info -> FoundY        = 0;
  902.                         LastSearchPosition    = 0;
  903.                     }
  904.                     else
  905.                     {
  906.                             /* Proceed to the next line. */
  907.  
  908.                         if(!(LastSearchPosition = Info -> Index))
  909.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  910.                     }
  911.  
  912.                         /* Run down the buffer. */
  913.  
  914.                     for(i = Info -> FoundY ; i < Lines ; i++)
  915.                     {
  916.                         Line = BufferLines[i];
  917.  
  918.                             /* Is there anything to search for? */
  919.  
  920.                         if((LineWidth = Line[-1]) >= PatternWidth)
  921.                         {
  922.                                 /* Where are we to start searching? */
  923.  
  924.                             if(LastSearchPosition)
  925.                                 SearchPosition = LastSearchPosition;
  926.                             else
  927.                                 SearchPosition = PatternWidth;
  928.  
  929.                             do
  930.                             {
  931.                                     /* How many line characters
  932.                                      * match the pattern?
  933.                                      */
  934.  
  935.                                 PatternIndex    = PatternWidth - 1;
  936.                                 LineIndex    = SearchPosition - 1;
  937.  
  938.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  939.                                 {
  940.                                     LineIndex--;
  941.                                     PatternIndex--;
  942.                                 }
  943.  
  944.                                     /* Update the line search index
  945.                                      * for subsequent searches.
  946.                                      */
  947.  
  948.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  949.  
  950.                                     /* Found the pattern? */
  951.  
  952.                                 if(PatternIndex < 0)
  953.                                 {
  954.                                     LONG X = LineIndex + 1;
  955.  
  956.                                     if(X)
  957.                                     {
  958.                                         if(!WordSeparators[Line[X - 1]])
  959.                                             continue;
  960.                                         else
  961.                                         {
  962.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  963.                                                 continue;
  964.                                         }
  965.                                     }
  966.                                     else
  967.                                     {
  968.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  969.                                             continue;
  970.                                     }
  971.  
  972.                                         /* Store the position. */
  973.  
  974.                                     Info -> FoundX    = LineIndex + 1;
  975.                                     Info -> FoundY    = i;
  976.  
  977.                                         /* Remember column to start
  978.                                          * next search attempt at.
  979.                                          */
  980.  
  981.                                     if(SearchPosition <= LineWidth)
  982.                                         Info -> Index = SearchPosition;
  983.                                     else
  984.                                         Info -> Index = 0;
  985.  
  986.                                     return(i);
  987.                                 }
  988.                             }
  989.                             while(SearchPosition <= LineWidth);
  990.                         }
  991.  
  992.                             /* Reset search column. */
  993.  
  994.                         LastSearchPosition = 0;
  995.                     }
  996.                 }
  997.                 else
  998.                 {
  999.                         /* Update the search positions. */
  1000.  
  1001.                     if(Info -> FoundY == -1)
  1002.                     {
  1003.                         Info -> FoundX        = 0;
  1004.                         Info -> FoundY        = Lines - 1;
  1005.                         LastSearchPosition    = 0;
  1006.                     }
  1007.                     else
  1008.                     {
  1009.                         if((LastSearchPosition = Info -> Index) < 1)
  1010.                         {
  1011.                             if(Info -> FoundY)
  1012.                                 Info -> FoundY--;
  1013.                             else
  1014.                                 Info -> FoundY = Lines - 1;
  1015.                         }
  1016.                     }
  1017.  
  1018.                         /* Run down the buffer. */
  1019.  
  1020.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  1021.                     {
  1022.                         Line = BufferLines[i];
  1023.  
  1024.                             /* Is there anything to search for? */
  1025.  
  1026.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1027.                         {
  1028.                                 /* Cast the magic spell of Boyer-Moore... */
  1029.  
  1030.                             if(LastSearchPosition < 1)
  1031.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1032.                             else
  1033.                                 SearchPosition = LastSearchPosition;
  1034.  
  1035.                             do
  1036.                             {
  1037.                                 PatternIndex = 0;
  1038.                                 LineIndex = SearchPosition - 1;
  1039.  
  1040.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  1041.                                 {
  1042.                                     LineIndex++;
  1043.                                     PatternIndex++;
  1044.                                 }
  1045.  
  1046.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  1047.  
  1048.                                 if(PatternIndex == PatternWidth)
  1049.                                 {
  1050.                                     LONG X = LineIndex - PatternWidth;
  1051.  
  1052.                                     if(X)
  1053.                                     {
  1054.                                         if(!WordSeparators[Line[X - 1]])
  1055.                                             continue;
  1056.                                         else
  1057.                                         {
  1058.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  1059.                                                 continue;
  1060.                                         }
  1061.                                     }
  1062.                                     else
  1063.                                     {
  1064.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  1065.                                             continue;
  1066.                                     }
  1067.  
  1068.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1069.                                     Info -> FoundY    = i;
  1070.                                     Info -> Index    = SearchPosition;
  1071.  
  1072.                                     return(i);
  1073.                                 }
  1074.                             }
  1075.                             while(SearchPosition > 0);
  1076.                         }
  1077.  
  1078.                         LastSearchPosition = 0;
  1079.                     }
  1080.                 }
  1081.             }
  1082.             else
  1083.             {
  1084.                 if(Info -> Forward)
  1085.                 {
  1086.                         /* Update the search positions. */
  1087.  
  1088.                     if(Info -> FoundY == -1)
  1089.                     {
  1090.                         Info -> FoundX        = 0;
  1091.                         Info -> FoundY        = 0;
  1092.                         LastSearchPosition    = 0;
  1093.                     }
  1094.                     else
  1095.                     {
  1096.                             /* Proceed to the next line. */
  1097.  
  1098.                         if(!(LastSearchPosition = Info -> Index))
  1099.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  1100.                     }
  1101.  
  1102.                         /* Run down the buffer. */
  1103.  
  1104.                     for(i = Info -> FoundY ; i < Lines ; i++)
  1105.                     {
  1106.                         Line = BufferLines[i];
  1107.  
  1108.                             /* Is there anything to search for? */
  1109.  
  1110.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1111.                         {
  1112.                                 /* Where are we to start searching? */
  1113.  
  1114.                             if(LastSearchPosition)
  1115.                                 SearchPosition = LastSearchPosition;
  1116.                             else
  1117.                                 SearchPosition = PatternWidth;
  1118.  
  1119.                             do
  1120.                             {
  1121.                                     /* How many line characters
  1122.                                      * match the pattern?
  1123.                                      */
  1124.  
  1125.                                 PatternIndex    = PatternWidth - 1;
  1126.                                 LineIndex    = SearchPosition - 1;
  1127.  
  1128.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  1129.                                 {
  1130.                                     LineIndex--;
  1131.                                     PatternIndex--;
  1132.                                 }
  1133.  
  1134.                                     /* Update the line search index
  1135.                                      * for subsequent searches.
  1136.                                      */
  1137.  
  1138.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  1139.  
  1140.                                     /* Found the pattern? */
  1141.  
  1142.                                 if(PatternIndex < 0)
  1143.                                 {
  1144.                                     LONG X = LineIndex + 1;
  1145.  
  1146.                                     if(X)
  1147.                                     {
  1148.                                         if(!WordSeparators[Line[X - 1]])
  1149.                                             continue;
  1150.                                         else
  1151.                                         {
  1152.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  1153.                                                 continue;
  1154.                                         }
  1155.                                     }
  1156.                                     else
  1157.                                     {
  1158.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  1159.                                             continue;
  1160.                                     }
  1161.  
  1162.                                         /* Store the position. */
  1163.  
  1164.                                     Info -> FoundX    = LineIndex + 1;
  1165.                                     Info -> FoundY    = i;
  1166.  
  1167.                                         /* Remember column to start
  1168.                                          * next search attempt at.
  1169.                                          */
  1170.  
  1171.                                     if(SearchPosition <= LineWidth)
  1172.                                         Info -> Index = SearchPosition;
  1173.                                     else
  1174.                                         Info -> Index = 0;
  1175.  
  1176.                                     return(i);
  1177.                                 }
  1178.                             }
  1179.                             while(SearchPosition <= LineWidth);
  1180.                         }
  1181.  
  1182.                             /* Reset search column. */
  1183.  
  1184.                         LastSearchPosition = 0;
  1185.                     }
  1186.                 }
  1187.                 else
  1188.                 {
  1189.                         /* Update the search positions. */
  1190.  
  1191.                     if(Info -> FoundY == -1)
  1192.                     {
  1193.                         Info -> FoundX        = 0;
  1194.                         Info -> FoundY        = Lines - 1;
  1195.                         LastSearchPosition    = 0;
  1196.                     }
  1197.                     else
  1198.                     {
  1199.                         if((LastSearchPosition = Info -> Index) < 1)
  1200.                         {
  1201.                             if(Info -> FoundY)
  1202.                                 Info -> FoundY--;
  1203.                             else
  1204.                                 Info -> FoundY = Lines - 1;
  1205.                         }
  1206.                     }
  1207.  
  1208.                         /* Run down the buffer. */
  1209.  
  1210.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  1211.                     {
  1212.                         Line = BufferLines[i];
  1213.  
  1214.                             /* Is there anything to search for? */
  1215.  
  1216.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1217.                         {
  1218.                                 /* Cast the magic spell of Boyer-Moore... */
  1219.  
  1220.                             if(LastSearchPosition < 1)
  1221.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1222.                             else
  1223.                                 SearchPosition = LastSearchPosition;
  1224.  
  1225.                             do
  1226.                             {
  1227.                                 PatternIndex = 0;
  1228.                                 LineIndex = SearchPosition - 1;
  1229.  
  1230.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  1231.                                 {
  1232.                                     LineIndex++;
  1233.                                     PatternIndex++;
  1234.                                 }
  1235.  
  1236.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  1237.  
  1238.                                 if(PatternIndex == PatternWidth)
  1239.                                 {
  1240.                                     LONG X = LineIndex - PatternWidth;
  1241.  
  1242.                                     if(X)
  1243.                                     {
  1244.                                         if(!WordSeparators[Line[X - 1]])
  1245.                                             continue;
  1246.                                         else
  1247.                                         {
  1248.                                             if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  1249.                                                 continue;
  1250.                                         }
  1251.                                     }
  1252.                                     else
  1253.                                     {
  1254.                                         if(X + PatternWidth < LineWidth && !WordSeparators[Line[X + PatternWidth]])
  1255.                                             continue;
  1256.                                     }
  1257.  
  1258.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1259.                                     Info -> FoundY    = i;
  1260.                                     Info -> Index    = SearchPosition;
  1261.  
  1262.                                     return(i);
  1263.                                 }
  1264.                             }
  1265.                             while(SearchPosition > 0);
  1266.                         }
  1267.  
  1268.                         LastSearchPosition = 0;
  1269.                     }
  1270.                 }
  1271.             }
  1272.         }
  1273.         else
  1274.         {
  1275.                 /* Which direction are we to search? */
  1276.  
  1277.             if(Info -> IgnoreCase)
  1278.             {
  1279.                 if(Info -> Forward)
  1280.                 {
  1281.                         /* Update the search positions. */
  1282.  
  1283.                     if(Info -> FoundY == -1)
  1284.                     {
  1285.                         Info -> FoundX        = 0;
  1286.                         Info -> FoundY        = 0;
  1287.                         LastSearchPosition    = 0;
  1288.                     }
  1289.                     else
  1290.                     {
  1291.                             /* Proceed to the next line. */
  1292.  
  1293.                         if(!(LastSearchPosition = Info -> Index))
  1294.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  1295.                     }
  1296.  
  1297.                         /* Run down the buffer. */
  1298.  
  1299.                     for(i = Info -> FoundY ; i < Lines ; i++)
  1300.                     {
  1301.                         Line = BufferLines[i];
  1302.  
  1303.                             /* Is there anything to search for? */
  1304.  
  1305.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1306.                         {
  1307.                                 /* Where are we to start searching? */
  1308.  
  1309.                             if(LastSearchPosition)
  1310.                                 SearchPosition = LastSearchPosition;
  1311.                             else
  1312.                                 SearchPosition = PatternWidth;
  1313.  
  1314.                             do
  1315.                             {
  1316.                                     /* How many line characters
  1317.                                      * match the pattern?
  1318.                                      */
  1319.  
  1320.                                 PatternIndex    = PatternWidth - 1;
  1321.                                 LineIndex    = SearchPosition - 1;
  1322.  
  1323.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  1324.                                 {
  1325.                                     LineIndex--;
  1326.                                     PatternIndex--;
  1327.                                 }
  1328.  
  1329.                                     /* Update the line search index
  1330.                                      * for subsequent searches.
  1331.                                      */
  1332.  
  1333.                                 SearchPosition += Distance[ToUpper(Line[SearchPosition - 1])];
  1334.  
  1335.                                     /* Found the pattern? */
  1336.  
  1337.                                 if(PatternIndex < 0)
  1338.                                 {
  1339.                                         /* Store the position. */
  1340.  
  1341.                                     Info -> FoundX    = LineIndex + 1;
  1342.                                     Info -> FoundY    = i;
  1343.  
  1344.                                         /* Remember column to start
  1345.                                          * next search attempt at.
  1346.                                          */
  1347.  
  1348.                                     if(SearchPosition <= LineWidth)
  1349.                                         Info -> Index = SearchPosition;
  1350.                                     else
  1351.                                         Info -> Index = 0;
  1352.  
  1353.                                     return(i);
  1354.                                 }
  1355.                             }
  1356.                             while(SearchPosition <= LineWidth);
  1357.                         }
  1358.  
  1359.                             /* Reset search column. */
  1360.  
  1361.                         LastSearchPosition = 0;
  1362.                     }
  1363.                 }
  1364.                 else
  1365.                 {
  1366.                         /* Update the search positions. */
  1367.  
  1368.                     if(Info -> FoundY == -1)
  1369.                     {
  1370.                         Info -> FoundX        = 0;
  1371.                         Info -> FoundY        = Lines - 1;
  1372.                         LastSearchPosition    = 0;
  1373.                     }
  1374.                     else
  1375.                     {
  1376.                         if((LastSearchPosition = Info -> Index) < 1)
  1377.                         {
  1378.                             if(Info -> FoundY)
  1379.                                 Info -> FoundY--;
  1380.                             else
  1381.                                 Info -> FoundY = Lines - 1;
  1382.                         }
  1383.                     }
  1384.  
  1385.                         /* Run down the buffer. */
  1386.  
  1387.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  1388.                     {
  1389.                         Line = BufferLines[i];
  1390.  
  1391.                             /* Is there anything to search for? */
  1392.  
  1393.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1394.                         {
  1395.                                 /* Cast the magic spell of Boyer-Moore... */
  1396.  
  1397.                             if(LastSearchPosition < 1)
  1398.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1399.                             else
  1400.                                 SearchPosition = LastSearchPosition;
  1401.  
  1402.                             do
  1403.                             {
  1404.                                 PatternIndex = 0;
  1405.                                 LineIndex = SearchPosition - 1;
  1406.  
  1407.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == ToUpper(Line[LineIndex]))
  1408.                                 {
  1409.                                     LineIndex++;
  1410.                                     PatternIndex++;
  1411.                                 }
  1412.  
  1413.                                 SearchPosition -= Distance[ToUpper(Line[SearchPosition - 1])];
  1414.  
  1415.                                 if(PatternIndex == PatternWidth)
  1416.                                 {
  1417.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1418.                                     Info -> FoundY    = i;
  1419.                                     Info -> Index    = SearchPosition;
  1420.  
  1421.                                     return(i);
  1422.                                 }
  1423.                             }
  1424.                             while(SearchPosition > 0);
  1425.                         }
  1426.  
  1427.                         LastSearchPosition = 0;
  1428.                     }
  1429.                 }
  1430.             }
  1431.             else
  1432.             {
  1433.                 if(Info -> Forward)
  1434.                 {
  1435.                         /* Update the search positions. */
  1436.  
  1437.                     if(Info -> FoundY == -1)
  1438.                     {
  1439.                         Info -> FoundX        = 0;
  1440.                         Info -> FoundY        = 0;
  1441.                         LastSearchPosition    = 0;
  1442.                     }
  1443.                     else
  1444.                     {
  1445.                             /* Proceed to the next line. */
  1446.  
  1447.                         if(!(LastSearchPosition = Info -> Index))
  1448.                             Info -> FoundY = (Info -> FoundY + 1) % Lines;
  1449.                     }
  1450.  
  1451.                         /* Run down the buffer. */
  1452.  
  1453.                     for(i = Info -> FoundY ; i < Lines ; i++)
  1454.                     {
  1455.                         Line = BufferLines[i];
  1456.  
  1457.                             /* Is there anything to search for? */
  1458.  
  1459.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1460.                         {
  1461.                                 /* Where are we to start searching? */
  1462.  
  1463.                             if(LastSearchPosition)
  1464.                                 SearchPosition = LastSearchPosition;
  1465.                             else
  1466.                                 SearchPosition = PatternWidth;
  1467.  
  1468.                             do
  1469.                             {
  1470.                                     /* How many line characters
  1471.                                      * match the pattern?
  1472.                                      */
  1473.  
  1474.                                 PatternIndex    = PatternWidth - 1;
  1475.                                 LineIndex    = SearchPosition - 1;
  1476.  
  1477.                                 while(PatternIndex >= 0 && Pattern[PatternIndex] == Line[LineIndex])
  1478.                                 {
  1479.                                     LineIndex--;
  1480.                                     PatternIndex--;
  1481.                                 }
  1482.  
  1483.                                     /* Update the line search index
  1484.                                      * for subsequent searches.
  1485.                                      */
  1486.  
  1487.                                 SearchPosition += Distance[Line[SearchPosition - 1]];
  1488.  
  1489.                                     /* Found the pattern? */
  1490.  
  1491.                                 if(PatternIndex < 0)
  1492.                                 {
  1493.                                         /* Store the position. */
  1494.  
  1495.                                     Info -> FoundX    = LineIndex + 1;
  1496.                                     Info -> FoundY    = i;
  1497.  
  1498.                                         /* Remember column to start
  1499.                                          * next search attempt at.
  1500.                                          */
  1501.  
  1502.                                     if(SearchPosition <= LineWidth)
  1503.                                         Info -> Index = SearchPosition;
  1504.                                     else
  1505.                                         Info -> Index = 0;
  1506.  
  1507.                                     return(i);
  1508.                                 }
  1509.                             }
  1510.                             while(SearchPosition <= LineWidth);
  1511.                         }
  1512.  
  1513.                             /* Reset search column. */
  1514.  
  1515.                         LastSearchPosition = 0;
  1516.                     }
  1517.                 }
  1518.                 else
  1519.                 {
  1520.                         /* Update the search positions. */
  1521.  
  1522.                     if(Info -> FoundY == -1)
  1523.                     {
  1524.                         Info -> FoundX        = 0;
  1525.                         Info -> FoundY        = Lines - 1;
  1526.                         LastSearchPosition    = 0;
  1527.                     }
  1528.                     else
  1529.                     {
  1530.                         if((LastSearchPosition = Info -> Index) < 1)
  1531.                         {
  1532.                             if(Info -> FoundY)
  1533.                                 Info -> FoundY--;
  1534.                             else
  1535.                                 Info -> FoundY = Lines - 1;
  1536.                         }
  1537.                     }
  1538.  
  1539.                         /* Run down the buffer. */
  1540.  
  1541.                     for(i = Info -> FoundY ; i >= 0 ; i--)
  1542.                     {
  1543.                         Line = BufferLines[i];
  1544.  
  1545.                             /* Is there anything to search for? */
  1546.  
  1547.                         if((LineWidth = Line[-1]) >= PatternWidth)
  1548.                         {
  1549.                                 /* Cast the magic spell of Boyer-Moore... */
  1550.  
  1551.                             if(LastSearchPosition < 1)
  1552.                                 SearchPosition = LineWidth - (PatternWidth - 1);
  1553.                             else
  1554.                                 SearchPosition = LastSearchPosition;
  1555.  
  1556.                             do
  1557.                             {
  1558.                                 PatternIndex = 0;
  1559.                                 LineIndex = SearchPosition - 1;
  1560.  
  1561.                                 while(PatternIndex < PatternWidth && Pattern[PatternIndex] == Line[LineIndex])
  1562.                                 {
  1563.                                     LineIndex++;
  1564.                                     PatternIndex++;
  1565.                                 }
  1566.  
  1567.                                 SearchPosition -= Distance[Line[SearchPosition - 1]];
  1568.  
  1569.                                 if(PatternIndex == PatternWidth)
  1570.                                 {
  1571.                                     Info -> FoundX    = LineIndex - PatternWidth;
  1572.                                     Info -> FoundY    = i;
  1573.                                     Info -> Index    = SearchPosition;
  1574.  
  1575.                                     return(i);
  1576.                                 }
  1577.                             }
  1578.                             while(SearchPosition > 0);
  1579.                         }
  1580.  
  1581.                         LastSearchPosition = 0;
  1582.                     }
  1583.                 }
  1584.             }
  1585.         }
  1586.     }
  1587.  
  1588.     return(-1);
  1589. }
  1590.  
  1591. STATIC ULONG __asm __saveds
  1592. HistoryFunc(register __a0 struct Hook *Hook,register __a1 STRPTR NewString)
  1593. {
  1594.     struct List *List = (struct List *)Hook -> h_Data;
  1595.  
  1596.     if(NewString)
  1597.     {
  1598.         struct Node *Node = CreateNode(NewString);
  1599.  
  1600.         if(Node)
  1601.             AddTail(List,Node);
  1602.         else
  1603.             return(FALSE);
  1604.     }
  1605.     else
  1606.     {
  1607.         struct Node *Node = RemHead(List);
  1608.  
  1609.         FreeNode(Node);
  1610.     }
  1611.  
  1612.     return(TRUE);
  1613. }
  1614.  
  1615. BOOLEAN __regargs
  1616. HandleSearchMessage(struct SearchContext *Context,struct IntuiMessage **MessagePtr)
  1617. {
  1618.     struct IntuiMessage    *Message;
  1619.     BOOLEAN             Done = FALSE;
  1620.  
  1621.     if(Message = GT_FilterIMsg(*MessagePtr))
  1622.     {
  1623.         ULONG         MsgClass    = Message -> Class,
  1624.                  MsgQualifier    = Message -> Qualifier;
  1625.         struct Gadget    *MsgGadget    = (struct Gadget *)Message -> IAddress;
  1626.         UWORD         MsgCode    = Message -> Code;
  1627.  
  1628.         LT_HandleInput(Context -> SearchHandle,MsgQualifier,&MsgClass,&MsgCode,&MsgGadget);
  1629.  
  1630.         if(MsgClass == IDCMP_CLOSEWINDOW)
  1631.             Done = TRUE;
  1632.  
  1633.         if(MsgClass == IDCMP_GADGETUP)
  1634.         {
  1635.             switch(MsgGadget -> GadgetID)
  1636.             {
  1637.                 case GAD_STRING:
  1638.  
  1639.                     if(MsgCode == '\r')
  1640.                     {
  1641.                         if(Context -> LocalBuffer[0])
  1642.                         {
  1643.                             strcpy(Context -> Buffer,Context -> LocalBuffer);
  1644.  
  1645.                             Context -> Ok = TRUE;
  1646.  
  1647.                             LT_PressButton(Context -> SearchHandle,GAD_OK);
  1648.                         }
  1649.                         else
  1650.                             LT_PressButton(Context -> SearchHandle,GAD_CANCEL);
  1651.  
  1652.                         Done = TRUE;
  1653.                     }
  1654.  
  1655.                     break;
  1656.  
  1657.                 case GAD_OK:
  1658.  
  1659.                     if(Context -> LocalBuffer[0])
  1660.                     {
  1661.                         strcpy(Context -> Buffer,Context -> LocalBuffer);
  1662.  
  1663.                         Context -> Ok = TRUE;
  1664.                     }
  1665.  
  1666.                     Done = TRUE;
  1667.  
  1668.                     break;
  1669.  
  1670.                 case GAD_CANCEL:
  1671.  
  1672.                     Done = TRUE;
  1673.  
  1674.                     break;
  1675.             }
  1676.         }
  1677.  
  1678.         GT_PostFilterIMsg(Message);
  1679.     }
  1680.  
  1681.     ReplyMsg(*MessagePtr);
  1682.  
  1683.     *MessagePtr = NULL;
  1684.  
  1685.     return(Done);
  1686. }
  1687.  
  1688. VOID __regargs
  1689. DeleteSearchContext(struct SearchContext *Context)
  1690. {
  1691.     if(Context)
  1692.     {
  1693.         LT_DeleteHandle(Context -> SearchHandle);
  1694.  
  1695.         DISPOSE(Context);
  1696.     }
  1697. }
  1698.  
  1699. struct SearchContext * __regargs
  1700. CreateSearchContext(struct Window *ParentWindow,STRPTR Buffer,struct Hook *HistoryHook,BOOLEAN *Forward,BOOLEAN *IgnoreCase,BOOLEAN *WholeWords)
  1701. {
  1702.     struct SearchContext *Context;
  1703.  
  1704.     if(NEW(Context))
  1705.     {
  1706.         struct LayoutHandle *Handle;
  1707.  
  1708.         Context -> Buffer = Buffer;
  1709.  
  1710.         if(HistoryHook)
  1711.             HistoryHook -> h_Entry = (HOOKFUNC)HistoryFunc;
  1712.  
  1713.         if(Handle = LT_CreateHandleTags(ParentWindow -> WScreen,
  1714.             LH_LocaleHook,    &LocaleHook,
  1715.         TAG_DONE))
  1716.         {
  1717.             struct Window *Window;
  1718.  
  1719.             LT_New(Handle,
  1720.                 LA_Type,    VERTICAL_KIND,
  1721.             TAG_DONE);
  1722.             {
  1723.                 LT_New(Handle,
  1724.                     LA_Type,    HORIZONTAL_KIND,
  1725.                     LA_LabelText,    LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),
  1726.                 TAG_DONE);
  1727.                 {
  1728.                     LT_New(Handle,
  1729.                         LA_Type,    VERTICAL_KIND,
  1730.                     TAG_DONE);
  1731.                     {
  1732.                         LT_New(Handle,
  1733.                             LA_Type,        STRING_KIND,
  1734.                             LA_LabelID,        MSG_V36_0788,
  1735.                             LA_STRPTR,        Context -> LocalBuffer,
  1736.                             LA_Chars,        30,
  1737.                             LA_ID,            GAD_STRING,
  1738.                             LAST_HistoryLines,    MAX(Config -> CaptureConfig -> SearchHistory,1),
  1739.                             LAST_HistoryHook,    HistoryHook,
  1740.                             GTST_MaxChars,        255,
  1741.                         TAG_DONE);
  1742.  
  1743.                         LT_EndGroup(Handle);
  1744.                     }
  1745.  
  1746.                     LT_New(Handle,
  1747.                         LA_Type,    VERTICAL_KIND,
  1748.                     TAG_DONE);
  1749.                     {
  1750.                         LT_New(Handle,
  1751.                             LA_Type,    CHECKBOX_KIND,
  1752.                             LA_LabelID,    MSG_TERMBUFFER_SEARCH_FORWARD_TXT,
  1753.                             LA_BYTE,    Forward,
  1754.                         TAG_DONE);
  1755.  
  1756.                         LT_New(Handle,
  1757.                             LA_Type,    CHECKBOX_KIND,
  1758.                             LA_LabelID,    MSG_TEXTBUFFER_IGNORE_CASE_GAD,
  1759.                             LA_BYTE,    IgnoreCase,
  1760.                         TAG_DONE);
  1761.  
  1762.                         LT_New(Handle,
  1763.                             LA_Type,    CHECKBOX_KIND,
  1764.                             LA_LabelID,    MSG_SEARCH_ONLY_WHOLE_WORDS_TXT,
  1765.                             LA_BYTE,    WholeWords,
  1766.                         TAG_DONE);
  1767.  
  1768.                         LT_EndGroup(Handle);
  1769.                     }
  1770.  
  1771.                     LT_EndGroup(Handle);
  1772.                 }
  1773.  
  1774.                 LT_New(Handle,
  1775.                     LA_Type,    VERTICAL_KIND,
  1776.                 TAG_DONE);
  1777.                 {
  1778.                     LT_New(Handle,LA_Type,XBAR_KIND,LAXB_FullSize,TRUE,TAG_DONE);
  1779.  
  1780.                     LT_EndGroup(Handle);
  1781.                 }
  1782.  
  1783.                 LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1784.                     LAGR_SameSize,    TRUE,
  1785.                     LAGR_Spread,    TRUE,
  1786.                 TAG_DONE);
  1787.                 {
  1788.                     LT_New(Handle,
  1789.                         LA_Type,    BUTTON_KIND,
  1790.                         LA_LabelID,    MSG_TERMXPR_OKAY_GAD,
  1791.                         LA_ID,        GAD_OK,
  1792.                         LABT_ReturnKey,    TRUE,
  1793.                         LABT_ExtraFat,    TRUE,
  1794.                     TAG_DONE);
  1795.  
  1796.                     LT_New(Handle,
  1797.                         LA_Type,    BUTTON_KIND,
  1798.                         LA_LabelID,    MSG_GLOBAL_CANCEL_GAD,
  1799.                         LA_ID,        GAD_CANCEL,
  1800.                         LABT_EscKey,    TRUE,
  1801.                         LABT_ExtraFat,    TRUE,
  1802.                     TAG_DONE);
  1803.  
  1804.                     LT_EndGroup(Handle);
  1805.                 }
  1806.  
  1807.                 LT_EndGroup(Handle);
  1808.             }
  1809.  
  1810.             if(Window = LT_Layout(Handle,LocaleString(MSG_TERMBUFFER_ENTER_SEARCH_STRING_TXT),NULL,0,0,IDCMP_CLOSEWINDOW,0,
  1811.                 LAWN_HelpHook,        &GuideHook,
  1812.                 LAWN_Parent,        ParentWindow,
  1813.                 LAWN_UserPort,        ParentWindow -> UserPort,
  1814.                 WA_DepthGadget,        TRUE,
  1815.                 WA_CloseGadget,        TRUE,
  1816.                 WA_DragBar,        TRUE,
  1817.                 WA_RMBTrap,        TRUE,
  1818.                 WA_Activate,        TRUE,
  1819.             TAG_DONE))
  1820.             {
  1821.                 LT_Activate(Handle,GAD_STRING);
  1822.  
  1823.                 Context -> SearchHandle    = Handle;
  1824.                 Context -> SearchWindow = Window;
  1825.  
  1826.                 return(Context);
  1827.             }
  1828.         }
  1829.  
  1830.         DISPOSE(Context);
  1831.     }
  1832.  
  1833.     return(NULL);
  1834. }
  1835.